package com.n9.qq.android;

import com.n9.qq.client.AbstractProtocol;
import com.n9.qq.util.Crypter;
import com.n9.qq.util.Util;
import com.n9.qq.util.Validator;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.ByteBuffer;
import java.util.Objects;

/**
 * @author ice
 * @since 2019/2/18 9:42
 */
public class AqProtocol extends AbstractProtocol {
    private static final Logger log = LoggerFactory.getLogger(AqProtocol.class);

    private static final int MIN_DATA_LEN = 4;
    private static final int MAX_QQUIN_LEN = 16;

    @Override
    protected boolean doDecode(IoSession ioSession, IoBuffer ioBuffer, ProtocolDecoderOutput protocolDecoderOutput) throws Exception {
        AqContext aqContext = (AqContext) ioSession.getAttribute(AqContext.class);
        if (Objects.isNull(aqContext)) {
            log.error("aq上下文不存在,无法解析{}");
            return false;
        }

        final int remain = ioBuffer.remaining();
        if (remain < MIN_DATA_LEN) {
            return false;
        }

        ioBuffer.mark();
        int dataLen = ioBuffer.getInt();

        if (remain >= dataLen) {
            byte[] data = new byte[dataLen - 4];
            ioBuffer.get(data);
            log.info("接收数据：{}", Util.convertByteToHexString(data));

            ByteBuffer buf = ByteBuffer.wrap(data);
            buf.get();
            final int cmd = buf.getInt();
            buf.get();
            int qqUinLen = buf.getInt() - 4;

            if (qqUinLen > MAX_QQUIN_LEN) {
                log.error("解密错误:{}:", Util.convertByteToHexString(data));
                return true;
            }
            byte[] qqUinBytes = new byte[qqUinLen];
            buf.get(qqUinBytes);
            long qqUin = Long.parseLong(new String(qqUinBytes));

            byte[] enData = new byte[buf.remaining()];
            buf.get(enData);
            byte[] key = null;
            switch (cmd) {
                //new byte[16]
                case 0x0802:
                case 0X0902:
                    key = aqContext.getDefaultKey();
                    break;
                //sessionKey
                case 0x0801:
                case 0x0901:
                    key = aqContext.getSessionKey();
                    break;
                default:
                    log.error("unknow cmd :{}",  Util.convertByteToHexString(data));
            }

            byte[] decryptData = new Crypter().decrypt(enData, key);
            if (Objects.isNull(decryptData)) {
                log.error("解密失败:{}", Util.convertByteToHexString(data));
            } else {
                AqFromServiceMsg fromServiceMsg = new AqFromServiceMsg(cmd, qqUin);
                fromServiceMsg.read(decryptData);

                RespHead respHead = fromServiceMsg.getRespHead();
                byte[] cookie = respHead.getCookie();
                if (Objects.nonNull(cookie) && cookie.length > 0) {
                    aqContext.setCookie(cookie);
                }
                protocolDecoderOutput.write(fromServiceMsg);
            }
            return true;
        } else {
            ioBuffer.reset();
            return false;
        }
    }

    @Override
    public void encode(IoSession ioSession, Object o, ProtocolEncoderOutput protocolEncoderOutput) throws Exception {
        if (Objects.nonNull(o) && o instanceof AqToServiceMsg) {
            AqToServiceMsg toServiceMsg = (AqToServiceMsg) o;
            byte[] bytes = toServiceMsg.getBytes();
            if (Validator.hasElement(bytes)) {
                log.info("发送数据:{}", Util.convertByteToHexString(bytes));

                IoBuffer buf = IoBuffer.allocate(bytes.length);
                buf.put(bytes);
                buf.flip();
                protocolEncoderOutput.write(buf);
            }
        }
    }
}
